package com.zuxia.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.zuxia.dto.DumpDto;
import com.zuxia.entity.Dump;
import com.zuxia.exception.ZuxiaBusinessException;
import com.zuxia.mapper.DumpMapper;
import com.zuxia.param.CoordinateParam;
import com.zuxia.service.DumpService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zuxia.utils.RedisUtils;
import com.zuxia.utils.ResultCodeEnum;
import org.springframework.data.geo.*;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author laoli
 * @since 2024-11-17
 */
@Service
public class DumpServiceImpl extends ServiceImpl<DumpMapper, Dump> implements DumpService {
    @Resource
    private DumpMapper dumpMapper;
    @Resource
    private RedisUtils redisUtil;

    @Override
    public List<DumpDto> getDumpByNear(CoordinateParam coordinateParam) {
        List<DumpDto> dumpDtos = new ArrayList<>();
        GeoResults<RedisGeoCommands.GeoLocation<Object>> locationGeoResults = redisUtil.getEDO(
                redisUtil.geoHouseKey(),
                new Circle(new Point(coordinateParam.getX(), coordinateParam.getY()),new Distance(0.05, RedisGeoCommands.DistanceUnit.KILOMETERS)));
        List<GeoResult<RedisGeoCommands.GeoLocation<Object>>> content = locationGeoResults.getContent();
        if(content.isEmpty()){
            List<Dump> dumps = dumpMapper.selectList(null);
            System.out.println(dumps);
            for (int i = 0; i < dumps.size(); i++) {
                Dump house = dumps.get(i);
                String[] coordinate = house.getDumpCoordinate().split(",");
                double latitude=Double.valueOf(coordinate[1]);
                double longitude=Double.valueOf(coordinate[0]);
                redisUtil.geoadd(redisUtil.geoHouseKey(),new Point(longitude,latitude), JSONUtil.toJsonStr(house));
            }
            content = redisUtil.getEDO(
                    redisUtil.geoHouseKey(),
                    new Circle(new Point(coordinateParam.getX(),coordinateParam.getY()),new Distance(10, RedisGeoCommands.DistanceUnit.KILOMETERS))).getContent();
            if(content.isEmpty()){
                return null;
            }
            List<Dump> houses = new ArrayList<>();
            for (GeoResult<RedisGeoCommands.GeoLocation<Object>> geoResult : content) {
                // 获取GeoLocation对象
                RedisGeoCommands.GeoLocation<Object> location = geoResult.getContent();
                Dump house =  JSON.parseObject(location.getName().toString(),Dump.class);
                System.out.println(house);
                houses.add(house);
                // 打印点的经纬度
                double longitude = Double.valueOf(String.format("%."+(coordinateParam.getX()+"").length()+"f",location.getPoint().getX()));
                double latitude = Double.valueOf(String.format("%."+(coordinateParam.getY()+"").length()+"f",location.getPoint().getY()));


                double v = haversineDistance(longitude,  latitude, coordinateParam.getX(),coordinateParam.getY());

                DumpDto dumpDto = BeanUtil.copyProperties(house, DumpDto.class);
                String m="km";
                if(v<1){
                    v*=1000;
                    m="m";
                }
                dumpDto.setM(v+m);
                dumpDtos.add(dumpDto);
            }
        }
        return dumpDtos;
    }

    @Override
    public Dump getDumpById(String id) {
        Dump dump = dumpMapper.selectById(id);
        if(dump==null){
            throw new ZuxiaBusinessException(ResultCodeEnum.DUMP_IS_NULL);
        }
        return dump;
    }

    private static double haversineDistance(double lat1, double lon1, double lat2, double lon2) {
        double EARTH_RADIUS = 6371.0;//6371000
        // 将角度转换为弧度
        double dLat = Math.toRadians(lat2 - lat1);
        double dLon = Math.toRadians(lon2 - lon1);
        lat1 = Math.toRadians(lat1);
        lat2 = Math.toRadians(lat2);

        // 应用Haversine公式
        double a = Math.pow(Math.sin(dLat / 2), 2) +
                Math.pow(Math.sin(dLon / 2), 2) * Math.cos(lat1) * Math.cos(lat2);
        double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
        return Double.valueOf(String.format("%.3f",EARTH_RADIUS * c));
    }
}
